package Util;

/**
 * 这个类是控制器的超类。中包含运行控制器作为线程。
 * 中提供了许多方法，这些方法允许执行器使用不同执行模式下的控制器。你的控制器只需要提供getMove（）方法的代码。
 *
 * @param <T> 要返回的移动的通用类型（Ms Pac-Man的单个移动或重影的EnumMap）。
 */

public abstract class Controller<T> implements Runnable {
    private boolean alive, wasSignalled, hasComputed;
    private volatile boolean threadStillRunning;
    private long timeDue;
    private Game game;
    protected T lastMove;//这现在是受保护的。您可以直接在getMove（）方法中设置它以保存即时响应。\

    public Controller() {
        alive = true;
        wasSignalled = false;
        hasComputed = false;
        threadStillRunning = false;
    }

    /**
     * 终止控制器：发送一个信号，标志“alive”设置为false。当线程唤醒时，外循环将终止，线程结束。
     */
    public final void terminate() {
        alive = false;
        wasSignalled = true;

        synchronized (this) {
            notify();
        }
    }

    /**
     * 更新游戏状态：将游戏的副本传递给此方法，并相应地更新类变量。
     *
     * @param game    当前游戏的副本
     * @param timeDue 下一步行动的时间
     */
    public final void update(Game game, long timeDue) {
        synchronized (this) {
            this.game = game;
            this.timeDue = timeDue;
            wasSignalled = true;
            hasComputed = false;
            notify();
        }
    }
    /**
     *从控制器检索移动（类变量中存储的任何内容）。
     *
     * @return 存储在类变量“lastMove”中的移动
     */
    public final T getMove()
    {
        return lastMove;
    }

    public final void run()
    {
        while(alive)
        {
            synchronized(this)
            {
                while(!wasSignalled)
                {
                    try
                    {
                        wait();
                    }
                    catch(InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }

                if(!threadStillRunning)
                {
                    new Thread()
                    {
                        public void run()
                        {
                            threadStillRunning=true;
                            lastMove = getMove(game,timeDue);
                            hasComputed=true;
                            threadStillRunning=false;
                        }
                    }.start();
                }

                wasSignalled=false;
            }
        }
    }
    /**
     * 此方法用于检查控制器是否计算了自上次更新游戏后的移动。
     * @return 控制器是否计算自上次更新后的移动
     */
    public final boolean hasComputed()
    {
        return hasComputed;
    }

    /**
     * 在给定当前游戏副本和移动时间的情况下计算下一步移动。
     * 这是参赛者需要实现的方法。在中提供了许多示例pacman.controllers.示例
     * @param game A copy of the current game
     * @param timeDue The time the next move is due
     * @return The move to be played (i.e., the move calculated by your controller)
     */
    public abstract T getMove(Game game,long timeDue);

}
